001 /*
002 * Copyright 2004-2005 Stephen J. McConnell.
003 * Copyright 2004 Niclas Hedhman
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
013 * implied.
014 *
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019 package net.dpml.transit.artifact;
020
021 import java.io.IOException;
022 import java.io.PrintWriter;
023
024 import java.net.URL;
025 import java.net.URLConnection;
026 import java.net.URLStreamHandler;
027 import java.security.AccessController;
028 import java.security.PrivilegedAction;
029
030 import net.dpml.transit.Transit;
031 import net.dpml.transit.TransitRuntimeException;
032 import net.dpml.transit.SecuredTransitContext;
033
034 /**
035 * The artifact URL protocol handler.
036 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
037 * @version 1.0.1
038 */
039 public class Handler extends URLStreamHandler
040 {
041 // ------------------------------------------------------------------------
042 // static
043 // ------------------------------------------------------------------------
044
045 /**
046 * Default buffer size.
047 */
048 private static final int BUFFER_SIZE = 100;
049
050 // ------------------------------------------------------------------------
051 // state
052 // ------------------------------------------------------------------------
053
054 /**
055 * The transit context.
056 */
057 private SecuredTransitContext m_context;
058
059 // ------------------------------------------------------------------------
060 // constructor
061 // ------------------------------------------------------------------------
062
063 /**
064 * Creation of a new transit artifact protocol handler.
065 */
066 public Handler()
067 {
068 try
069 {
070 Transit.getInstance();
071 m_context = SecuredTransitContext.getInstance();
072 }
073 catch( RuntimeException e )
074 {
075 e.printStackTrace();
076 throw e;
077 }
078 }
079
080 // ------------------------------------------------------------------------
081 // implementation
082 // ------------------------------------------------------------------------
083
084 /**
085 * Opens a connection to the specified URL.
086 *
087 * @param url A URL to open a connection to.
088 * @return The established connection.
089 * @throws IOException If a connection failure occurs.
090 */
091 protected URLConnection openConnection( final URL url )
092 throws IOException
093 {
094 return new ArtifactURLConnection( url, m_context );
095 }
096
097 /**
098 * Return the external representation of the supplied url.
099 * @param u the url
100 * @return a string representing of the url as an artifact uri
101 */
102 protected String toExternalForm( URL u )
103 {
104 StringBuffer buf = new StringBuffer( BUFFER_SIZE );
105 buf.append( u.getProtocol() );
106 buf.append( ":" );
107 String path = getRealPath( u );
108 if( path != null )
109 {
110 int lastPos = path.length() - 1;
111 if( path.charAt( lastPos ) == '/' )
112 {
113 buf.append( path.substring( 0, lastPos ) );
114 }
115 else
116 {
117 buf.append( path );
118 }
119 }
120
121 String internal = getInternalPath( u );
122 if( null != internal )
123 {
124 buf.append( internal );
125 }
126
127 String version = u.getUserInfo();
128 if( ( version != null ) && !"".equals( version ) )
129 {
130 buf.append( '#' );
131 buf.append( version );
132 }
133 String result = buf.toString();
134 buf.setLength( 0 );
135 return result;
136 }
137
138 /**
139 * Return the pure artifact path without any internal address.
140 * @param url the url to evaluate
141 * @return the pure path
142 */
143 private String getRealPath( URL url )
144 {
145 String path = url.getPath();
146 if( null == path )
147 {
148 return null;
149 }
150 int index = path.indexOf( "!" );
151 if( index < 0 )
152 {
153 return path;
154 }
155 else
156 {
157 return path.substring( 0, index );
158 }
159 }
160
161 /**
162 * Return the value of an internal address associated with a path.
163 * @param url the url to evaluate
164 * @return the internal address of null if the url does not contain an internal address
165 */
166 private String getInternalPath( URL url )
167 {
168 String path = url.getPath();
169 if( null == path )
170 {
171 return null;
172 }
173 int index = path.indexOf( "!" );
174 if( index < 0 )
175 {
176 return null;
177 }
178 else
179 {
180 return path.substring( index );
181 }
182 }
183
184
185 /**
186 * Parse the supplied specification.
187 * @param dest the destination url to populate
188 * @param spec the supplied spec
189 * @param start the starting position
190 * @param limit the limit
191 */
192 protected void parseURL( final URL dest, String spec, int start, int limit )
193 {
194 try
195 {
196 final String protocol = dest.getProtocol();
197 String specPath = spec.substring( start, limit );
198 String path = dest.getPath();
199
200 if( path == null )
201 {
202 path = specPath;
203 if( !path.endsWith( "/" ) && ( path.indexOf( "!" ) < 0 ) )
204 {
205 path = path + "/";
206 }
207 }
208 else
209 {
210 int lastPos = path.length() - 1;
211 if( path.charAt( lastPos ) == '/' )
212 {
213 path = path.substring( 0, lastPos );
214 }
215 if( specPath.charAt( 0 ) == '/' )
216 {
217 path = path + "!" + specPath;
218 }
219 else
220 {
221 path = path + "!/" + specPath;
222 }
223 }
224 String version = dest.getUserInfo();
225 if( version == null )
226 {
227 if( limit < spec.length() )
228 {
229 version = spec.substring( limit + 1 );
230 }
231 }
232 final String user = version;
233 final String authority = null;
234 final int port = -1;
235 final String host = null;
236 final String query = null;
237 final String ref = null;
238 final String finalPath = path;
239 AccessController.doPrivileged(
240 new PrivilegedAction()
241 {
242 public Object run()
243 {
244 setURL( dest, protocol, host, port, authority, user, finalPath, query, ref );
245 return null;
246 }
247 }
248 );
249 }
250 catch( Throwable e )
251 {
252 try
253 {
254 PrintWriter log = Transit.getInstance().getLogWriter();
255 String message = "Unable to parse the URL: "
256 + dest + ", " + spec + ", " + start + ", " + limit;
257 log.println( message );
258 log.println( "---------------------------------------------------" );
259 e.printStackTrace( log );
260 }
261 catch( TransitRuntimeException f )
262 {
263 // Panic!!!! Should not happen.
264 f.printStackTrace();
265 e.printStackTrace();
266 }
267 }
268 }
269 }